package com.rcklos.NettyLentMe.netty.handler;

import com.alibaba.fastjson.JSONObject;
import com.rcklos.NettyLentMe.ServerConfig;
import com.rcklos.NettyLentMe.ServerTransponder;
import com.rcklos.NettyLentMe.bean.ChatMessage;
import com.rcklos.NettyLentMe.match.MatchContainer;
import com.rcklos.NettyLentMe.match.MatchContainerInterface;
import com.rcklos.NettyLentMe.netty.channel.ChannelPool;
import com.rcklos.NettyLentMe.protocol.handler.ServiceHandler;
import com.rcklos.NettyLentMe.netty.NettyChannel;
import com.rcklos.NettyLentMe.protocol.protobuf.MessageProtobuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * modified at 2022年10月5日 13点31分
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

	private ServerTransponder transponder;
	private MatchContainerInterface matchContainer;
	private ChannelPool channelPool;
	private ServiceHandler connector;

//	public ServerHandler(){
//		channelPool = ChannelPool.getInstance();
//		connector = ServiceHandler.getInstance();
//	}
//
//	@Override
//	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
////		super.channelRead(ctx, msg);
//		connector.submitRead(ctx.channel(), (IMPackage.Msg)msg);
//	}
//
//	@Override
//	public void channelActive(ChannelHandlerContext ctx) throws Exception {
////		super.channelActive(ctx);
//		channelPool.put(ctx.channel());
//	}
//
//	@Override
//	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
////		super.channelInactive(ctx);
//		channelPool.del(ctx.channel());
//	}
//
//
//	@Override
//	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
////		super.exceptionCaught(ctx, cause);
//		channelPool.exceptionCaught(ctx.channel(), cause);
//	}
//
//	@Override
//	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//		// TODO Auto-generated method stub
//		super.userEventTriggered(ctx, evt);
//	}

/**
 * deprecated at 2020年10月5日 13点32分
 */

//	@Override
//	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//		// TODO Auto-generated method stub
//		super.exceptionCaught(ctx, cause);
//

//		System.out.println("连接异常-->cause:"  +cause.getMessage());
//
//	}

	public static class ChannelContainer{
		private static ChannelContainer instance = new ChannelContainer();
		public static ChannelContainer getInstance() {
			return instance;
		}

		private ChannelContainer() {
			// TODO Auto-generated constructor stub
		}

		private Map<String,NettyChannel> channels = new ConcurrentHashMap<String, NettyChannel>();

		public Channel getChannelByChannelId(String channelId){
			if( channels.containsKey(channelId) ){
				if (channels.get(channelId).getChannel().isActive())
					return channels.get(channelId).getChannel();
				else removeChannelIfInactiveByChannelId(channelId);
			}
			return null;
		}

		public Channel getChannelByUserId(String userid) {
			for ( Map.Entry<String,NettyChannel> entry : channels.entrySet() ){
				if ( entry.getValue().getUserId().equals(userid)){
					if (  entry.getValue().getChannel().isActive()  )
						return entry.getValue().getChannel();
					else removeChannelIfInactiveByChannelId(entry.getValue().getChannelId());
				}
			}
			return null;
		}

		public void removeChannelIfInactiveByChannelId(String channelId){
			if ( channels.containsKey(channelId) && !channels.get(channelId).getChannel().isActive() ){
				String userid = channels.get(channelId).getUserId();
				System.out.println("用户["+userid+"]已下线");
				channels.remove(channelId);
				System.out.println("当前在线人数："+channels.size()+"人");
				MatchContainer.getInstance().removeTokenByUserid(userid);
			}
		}

		public void saveChannel(NettyChannel channel) {
			channels.put(channel.getChannelId(),channel);
			System.out.println("用户["+channel.getUserId()+"]已上线");
			System.out.println("当前在线人数："+channels.size()+"人");
		}

		public void removeErrorChannel(){
			for ( Map.Entry<String,NettyChannel> entry : channels.entrySet() ){
				if ( entry.getValue().getChannel()!=null ){
					if ( !entry.getValue().getChannel().isActive() ){
						removeChannelIfInactiveByChannelId(entry.getValue().getChannelId());
					}
				} else {
					removeChannelIfInactiveByChannelId(entry.getValue().getChannelId());
				}
			}
		}
	}

	public ServerHandler(){
		transponder = ServerTransponder.getInstance();
		matchContainer = MatchContainer.getInstance();

	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelActive(ctx);
		System.out.println("有一个人上线了");
	}


	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelInactive(ctx);
		System.out.println("有一个人下线了");
		ChannelContainer.getInstance().removeChannelIfInactiveByChannelId(ctx.channel().id().toString());
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
//		super.channelRead(ctx, msg);
		// 发来的是不正常的封包
		if (! (msg instanceof MessageProtobuf.Msg) ) {
			System.out.println("存在一个不正常连接,即将强制断开该连接");
			ChannelContainer.getInstance().removeChannelIfInactiveByChannelId(ctx.channel().id().toString());

			/**
			 * modified at 2020年10月5日 13点34分
			 */
			channelPool.del(ctx.channel());
			return;
		}
		// 提取message
		MessageProtobuf.Msg message = (MessageProtobuf.Msg)msg;
		// 输出心跳包
		System.out.println("收到封包:"+message);
		int msgType = message.getHead().getMsgType();
		switch (msgType) {
			case ServerConfig.typeHeartBeat:
				//心跳消息
				//System.out.println("用户["+message.getHead().getFromId()+"]发来了心跳包");
				//发送回去
				transponder.sendMsg(transponder.genMsg(ServerConfig.typeHeartBeat,null,message.getHead().getFromId(),null,null));
				if (matchContainer.isQueueContainsUserAndContainsToken(message.getHead().getFromId())){
					transponder.sendStringSingleChatTime(message.getHead().getFromId());
				}
				break;
			case ServerConfig.typeLogin:
				//登录消息
				System.out.println("用户["+message.getHead().getFromId()+"]发来了登录信息:"+message.getHead().getExtend());
				//保存用户
				ChannelContainer.getInstance().saveChannel(new NettyChannel(message.getHead().getFromId(),ctx.channel()));
				//转发回去
				transponder.sendMsg(transponder.genMsg(ServerConfig.typeLogin,null,message.getHead().getFromId(),null,null));
				System.out.println("已将登录状态回发用户["+message.getHead().getFromId()+"]");
				break;
			case ServerConfig.typeMatch:
				System.out.println("用户["+message.getHead().getFromId()+"]发来了匹配请求:"+message.getHead().getExtend());
				//加入匹配队列
				matchContainer.addQueueByUserId(message.getHead().getFromId(),message.getHead().getExtend());
				break;
			case ServerConfig.typeSignTokenMessage:
				System.out.println("用户["+message.getHead().getFromId()+"]发来了信息:"+message.getHead().getExtend());
				String toId = matchContainer.getUserByToken(message.getHead().getToId(),message.getHead().getFromId());
				Channel channel = ChannelContainer.getInstance().getChannelByUserId(toId);
				if ( channel== null ){
					System.out.println("channel== null");
					//transponder.respond(message.getHead().getFromId(),"您匹配的好友已经离开了哦");
					transponder.sendInformTheSingleTokenDestroy(message.getHead().getFromId());
				} else {
					//转发消息
					transponder.sendMsg(transponder.genMsg(ServerConfig.typeSignTokenMessage,message.getHead().getFromId(),toId,null,message.getBody()));
					if ( ServerConfig.showChatContent ){
						ChatMessage chatMessage = JSONObject.parseObject(message.getBody(), ChatMessage.class);
						System.out.println("from ["+message.getHead().getFromId() + "] to ["+message.getHead().getToId() + "] " + "message:"+chatMessage.getContent());
					} else System.out.println("已转发消息给目标");
					transponder.sendStringSingleChatTime(message.getHead().getFromId());
				}
				break;
			case ServerConfig.typeMatchCancel:
				System.out.println("用户["+message.getHead().getFromId()+"]取消了匹配");
				matchContainer.removeTokenByUserid(message.getHead().getFromId());
				break;
			case ServerConfig.typeGetSingleChatTime:
				//将token中获取到的时间发回去
				transponder.sendStringSingleChatTime(message.getHead().getFromId());
			default:
				break;
		}
	}

}
